package behaviorTree

import (
	"fmt"
	"gitee.com/kingzyt/common/log"
)

type INode interface {
	GetName() string
	GetType() NodeType

	// Installation
	AddChild(child INode) INode
	CheckValidation() bool

	GetChildCount() int
	IteratorChildren(proc func(child INode) bool)

	//runtime
	Enter(data IRuntimeBTData, stateIn NodeState, localDataIn interface{}) (childNode INode, state NodeState, localDataOut interface{})
	RunningCheck(data IRuntimeBTData, localDataIn interface{}) (state NodeState, localDataOut interface{})

	//GetShowNameRect() (w int32, h int32)
	//GetShowRect() (w int32, h int32)
	//Show(x int32, y int32) (h int32)
}

// not completed implement of INode, just frame data api
type BaseNode struct {
	name     string
	nodeType NodeType
	children []INode

	AddChildFunc        func(child INode)
	CheckValidationFunc func() (rlt bool, errInfo string)
	RunningCheckFunc    func(data IRuntimeBTData, localDataIn interface{}) (state NodeState, localDataOut interface{})
}

func NewBaseNode(name string, nodeType NodeType) *BaseNode {
	return &BaseNode{name: UniqueName(name), nodeType: nodeType}
}

func (self *BaseNode) GetName() string {
	return self.name
}
func (self *BaseNode) GetType() NodeType {
	return self.nodeType
}

func (self *BaseNode) AddChild(child INode) INode {
	if child == nil {
		log.Panic(self.name, "child node cannot be nil")
	}

	if self.AddChildFunc != nil {
		self.AddChildFunc(child)
	} else {
		self.children = append(self.children, child)
	}
	return child
}

func (self *BaseNode) CheckValidation() bool {
	if self.CheckValidationFunc != nil {
		ok, errInfo := self.CheckValidationFunc()
		if !ok {
			log.Error(self.name, errInfo)
			return false
		}
	}

	clen := len(self.children)
	for i := 0; i < clen; i++ {
		child := self.children[i]
		if !child.CheckValidation() {
			return false
		}
	}
	return true
}

func (self *BaseNode) checkChildCnt(wantCnt int) (rlt bool, errInfo string) {
	rlt = len(self.children) == wantCnt
	if !rlt {
		errInfo = fmt.Sprintf("child count should be %d, now is %d", wantCnt, len(self.children))
	}
	return
}

func (self *BaseNode) checkChildCntOver0() (rlt bool, errInfo string) {
	rlt = len(self.children) > 0
	if !rlt {
		errInfo = "child count should be > 0"
	}
	return
}

func (self *BaseNode) GetChildCount() int {
	return len(self.children)
}
func (self *BaseNode) IteratorChildren(proc func(child INode) bool) {
	if proc == nil {
		return
	}

	for i := 0; i < len(self.children); i++ {
		if !proc(self.children[i]) {
			return
		}
	}
}

//只有Action和ActionWait的节点是允许有RUNNING态的,也就这两种节点可能会调用到这个接口
func (self *BaseNode) RunningCheck(data IRuntimeBTData, localDataIn interface{}) (state NodeState, localDataOut interface{}) {
	if self.nodeType != NodeType_Action && self.nodeType != NodeType_ActionWait {
		panic(fmt.Errorf("only action/actionwait have to check RUNNING state, current node type is %s", self.nodeType))
	}
	if self.RunningCheckFunc != nil {
		state, localDataOut = self.RunningCheckFunc(data, localDataIn)
		return
	}
	return FAILURE, localDataIn
}
